package com.njcb.ams.service;

import com.njcb.ams.factory.domain.AppContext;
import com.njcb.ams.pojo.dto.AccessToken;
import com.njcb.ams.pojo.dto.AccessTokenResponse;
import com.njcb.ams.pojo.dto.CheckTokenInfo;
import com.njcb.ams.pojo.dto.CheckTokenInfoResponse;
import com.njcb.ams.pojo.dto.standard.EntityResponse;
import com.njcb.ams.support.exception.ExceptionUtil;
import com.njcb.ams.support.security.bo.SecurityUser;
import com.njcb.ams.support.security.service.LoginSuccessAuthenticationHandler;
import com.njcb.ams.util.*;
import okhttp3.*;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author liuyanlong
 */
@Component
public class SsoClientService {
    /**
     * 是否启用SSO
     */
    private Boolean isSso = false;
    public Boolean ssoHandle(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        if(!isSso){
            return true;
        }
        String code = request.getParameter("code");
        String accessToken = request.getParameter("accessToken");
        String refreshToken = request.getParameter("refreshToken");
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Object principal = null;
        if (null != authentication) {
            principal = authentication.getPrincipal();
        }
        if (null == principal) {
            SecurityUser securityUser = null;
            String url = request.getRequestURL().toString();
            if(AmsUtils.isNotNull(accessToken)){
                AccessTokenResponse accessTokenResponse = new AccessTokenResponse();
                accessTokenResponse.setEntity(new AccessToken(accessToken));
                CheckTokenInfo checkTokenInfo = getCheckTokenInfoByToken(accessTokenResponse);
                securityUser = checkTokenInfoToSecurityUser(checkTokenInfo);
            }else if(AmsUtils.isNotNull(code)){
                CheckTokenInfo checkTokenInfo = getCheckTokenInfoByCode(code, url);
                securityUser = checkTokenInfoToSecurityUser(checkTokenInfo);
            }else{
                return false;
            }
            if(null != securityUser){
                Authentication authRequest = new UsernamePasswordAuthenticationToken(securityUser, null, securityUser.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(authRequest);
                LoginSuccessAuthenticationHandler successHandler = AppContext.getBean(LoginSuccessAuthenticationHandler.class);
                successHandler.securityUserHandle(request);
            }
        }
        return true;
    }

    public void ssoRedirect(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String url = request.getRequestURL().toString();
        String redirectUrl = "http://trythis.cn:20000/ams-sso/authorize/code?client_id=client&redirect_uri="+url+"&response_type=code&scope=all&state=9999";
        if(AmsHttpUtils.isAjaxRequest(request)){
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/json;charset=utf-8");
            ServletOutputStream out = response.getOutputStream();
            EntityResponse entityResponse = EntityResponse.buildFail(AmsCollectionUtils.newHashMap("redirectUrl",redirectUrl),"302","请进入SSO认证");
            out.write(AmsJsonUtils.objectToJson(entityResponse).getBytes("UTF-8"));
            out.flush();
        }else{
            response.sendRedirect(redirectUrl);
        }
    }

    private SecurityUser checkTokenInfoToSecurityUser(CheckTokenInfo checkTokenInfo) {
        SecurityUser securityUser = new SecurityUser();
        securityUser.setId(checkTokenInfo.getId());
        securityUser.setRoleCodes(checkTokenInfo.getAuthorities());
        securityUser.setLoginName(checkTokenInfo.getUserName());
        securityUser.setUserName(checkTokenInfo.getUserName());
        securityUser.setOrgnNo(checkTokenInfo.getOrgnNo());
        securityUser.setOrgnName(checkTokenInfo.getOrgnName());
        securityUser.setBusiDate(SysInfoUtils.getBusiDate());
        securityUser.setEmpNo(checkTokenInfo.getEmpNo());
        return securityUser;
    }

    private CheckTokenInfo getCheckTokenInfoByCode(String code, String url) throws IOException {
        OkHttpClient okHttpClient = new OkHttpClient();
        RequestBody codeBody = new FormBody.Builder()
                .add("code", code)
                .add("redirect_uri", url)
                .build();
        Request clientCodeRequest = new Request.Builder()
                .url("http://trythis.cn:20000/ams-sso/token/code")
                .post(codeBody)
                .addHeader("Authorization", "Basic Y2xpZW50OnNlY3JldA==")
                .build();
        Response clientCodeResponse = okHttpClient.newCall(clientCodeRequest).execute();
        String codeBodyStr = new String(clientCodeResponse.body().bytes());
        AccessTokenResponse accessTokenResponse = AmsJsonUtils.jsonToObject(codeBodyStr, AccessTokenResponse.class);
        if (!accessTokenResponse.isSuccess()) {
            ExceptionUtil.throwAppException(accessTokenResponse.getMessage());
        }
        return getCheckTokenInfoByToken(accessTokenResponse);
    }

    private CheckTokenInfo getCheckTokenInfoByToken(AccessTokenResponse accessTokenResponse) throws IOException {
        OkHttpClient okHttpClient = new OkHttpClient();
        RequestBody tokenBody = new FormBody.Builder()
                .add("token", accessTokenResponse.getEntity().getAccessToken())
                .build();
        Request clientTokenRequest = new Request.Builder()
                .url("http://trythis.cn:20000/ams-sso/check/token")
                .post(tokenBody)
                .addHeader("Authorization", "Basic Y2xpZW50OnNlY3JldA==")
                .build();
        Response clientTokenResponse = okHttpClient.newCall(clientTokenRequest).execute();
        String tokenBodyStr = new String(clientTokenResponse.body().bytes());
        CheckTokenInfoResponse checkTokenInfo = AmsJsonUtils.jsonToObject(tokenBodyStr, CheckTokenInfoResponse.class);
        if (!checkTokenInfo.isSuccess()) {
            ExceptionUtil.throwAppException(checkTokenInfo.getMessage());
        }
        return checkTokenInfo.getEntity();
    }
}